/** include predefined life command line options */
#include <life/options.hpp>

/** include linear algebra backend */
#include <life/lifealg/backend.hpp>

/** include function space class */
#include <life/lifediscr/functionspace.hpp>

/** include helper function to define \f$P_0\f$ functions associated with regions  */
#include <life/lifediscr/region.hpp>

/** include integration methods */
#include <life/lifepoly/im.hpp>
/** include gmsh mesh importer */
#include <life/lifefilters/gmsh.hpp>

/** include exporter factory class */
#include <life/lifefilters/exporter.hpp>

/** include gmsh generator for tensorized domains */
#include <life/lifefilters/gmshtensorizeddomain.hpp>

/** include  polynomialset header */
#include <life/lifepoly/polynomialset.hpp>

/** include  the header for the variational formulation language (vf) aka FEEL++ */
#include <life/lifevf/vf.hpp>

#include <fstream> 

/** use Life namespace */
using namespace Life;
using namespace Life::vf;



template<uint Dim,uint N>
class Interpolate
    :
    public Application
{
    typedef Application super;
public:

    //! Polynomial order \f$P_2\f$
//    static const uint16_type Order = 5;
    ///static const uint Order = N;

    //! numerical type is double
    typedef double value_type;

    //! linear algebra backend factory
    typedef Backend<value_type> backend_type;
    //! linear algebra backend factory shared_ptr<> type
    typedef boost::shared_ptr<backend_type> backend_ptrtype;


    //! sparse matrix type associated with backend
    typedef backend_type::sparse_matrix_type sparse_matrix_type;
    //! sparse matrix type associated with backend (shared_ptr<> type)
    typedef backend_type::sparse_matrix_ptrtype sparse_matrix_ptrtype;
    //! vector type associated with backend
    typedef backend_type::vector_type vector_type;
    //! vector type associated with backend (shared_ptr<> type)
    typedef backend_type::vector_ptrtype vector_ptrtype;

    //! geometry entities type composing the mesh, here Simplex in Dimension Dim of Order 1
    typedef Simplex<Dim> convex_type;
    //! mesh type
    typedef Mesh<convex_type> mesh_type;
    //! mesh shared_ptr<> type
    typedef boost::shared_ptr<mesh_type> mesh_ptrtype;

    //! the basis type of our approximation space
    //typedef bases<OrthonormalPolynomialSet<Order,Scalar> > basis_type;
    typedef bases<Lagrange</*Order*/N,Scalar,PointSetFekete> > basis_type;

    //! the approximation function space type
    typedef FunctionSpace<mesh_type, basis_type> space_type;
    //! the approximation function space type (shared_ptr<> type)
    typedef boost::shared_ptr<space_type> space_ptrtype;
    //! an element type of the approximation function space
    typedef typename space_type::element_type element_type;

    //! the exporter factory type
    typedef Exporter<mesh_type> export_type;
    //! the exporter factory (shared_ptr<> type)
    typedef boost::shared_ptr<export_type> export_ptrtype;

    /**
     * Constructor
     */
    Interpolate( int argc, char** argv, AboutData const& ad,
               po::options_description const& od )
        :
        super( argc, argv, ad, od ),
        M_backend( backend_type::build( this->vm() ) ),
        //M_backend( backend_type::build( BACKEND_TRILINOS ) ),
        meshSize( this->vm()["hsize"].template as<double>() ),
        exporter( Exporter<mesh_type>::New( this->vm(), this->about().appName() ) )
    {
    }

    // create the mesh using mesh size \c meshSize
    mesh_ptrtype createMesh( double meshSize );
    mesh_ptrtype createMesh1( double meshSize );
    mesh_ptrtype createMesh2( double meshSize );
    
    // run the application
    void run();
    void run2();

private:

    // solve the system \f$D u = F\f$
    // void solve( sparse_matrix_ptrtype& D, element_type& u, vector_ptrtype& F );
    
    // export results to ensight format (enabled by  --export cmd line options)
    // void exportResults( element_type& u );

private:

    // linear algebra backend
    backend_ptrtype M_backend;

    // mesh characteristic size
    double meshSize;

    // exporter factory
    export_ptrtype exporter;
}; // Interpolate

